#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
use crate::elf::elf_enum::*;
use std::convert::TryInto;
use num_traits::FromPrimitive;

pub mod elf_types;
pub mod elf_enum;
pub mod elf_machine;
pub mod elf32;

type Elf32_Addr = u32;
type Elf32_Off = u32;
type Elf32_Half = u16;
type Elf32_Word = u32;
type Elf32_Sword = i32;

type Elf64_Addr = u64;
type Elf64_Off = u64;
type Elf64_Half = u16;
type Elf64_Word = u32;
type Elf64_Sword = i32;
type Elf64_Xword = u64;
type Elf64_Sxword = i64;

pub fn elf_hash(name: &str) -> u32 {
    let name_bytes = name.as_bytes();
    let mut h :u32 = 0;
    for byte in name_bytes.iter() {
        h = (h << 4) + *byte as u32;
        let g :u32 = h & 0xF0000000;
        h ^= g;
        h ^= g >> 24;
    }
    return h;
}

pub fn gun_hash(name: &str) -> u32 {
    let name_bytes = name.as_bytes();
    let mut h :u32 = 5381;

    for byte in name_bytes.iter() {
        h += h << 5 + *byte as u32
    }
    return h;
}

#[inline]
pub fn elf_symbol_bind(info: u32) -> ElfSymbolBind {
    FromPrimitive::from_u32(info >> 4).unwrap()

    // let v = info >>4;
    // v.into()
}

#[inline]
pub fn elf_symbol_type(info: u32) -> ElfSymbolType {
    FromPrimitive::from_u32(info & 0xF).unwrap()
    // let v = info & 0xF;
    // v.into()
}

#[inline]
pub fn elf_symbol_visibility(other: u32) -> ElfSymbolVisibility {
    FromPrimitive::from_u32(other & 0x3).unwrap()
    // let val = other & 0x3;
    // val.into()
}

#[inline]
pub fn elf32_reloc_symndx(r_info: Elf32_Word) -> u32 {
    r_info >> 8
}

#[inline]
pub fn elf32_reloc_type(r_info: Elf32_Word) -> RelocationType {
    FromPrimitive::from_u32(r_info & 0xF).unwrap()
    // let val = r_info & 0xF;
    // val.into()
}

#[inline]
pub fn elf64_reloc_symndx(r_info: Elf64_Xword) -> u64 {
    r_info >> 32
}

#[inline]
pub fn elf64_reloc_type(r_info: Elf64_Xword) -> RelocationType {
    FromPrimitive::from_u32( (r_info & 0xffffffff) as u32 ).unwrap()
    // let val = r_info & 0xffffffff;
    // (val as u32).into()
}


pub fn vec_to_array<T, const N: usize>(v: Vec<T>) -> [T; N] {
    let boxed_slice = v.into_boxed_slice();
    let boxed_array: Box<[T; N]> = match boxed_slice.try_into() {
        Ok(ba) => ba,
        Err(o) => panic!("Expected a Vec of length {} but it was {}", N, o.len()),
    };
    *boxed_array
}

pub trait AsBytes {
    fn as_bytes(&self) -> Vec<u8>;
}


